package com.icesoft.system.auth.config;

import com.icesoft.framework.core.cache.RedisCacheManager;
import com.icesoft.system.auth.realm.AuthRealm;
import com.icesoft.system.auth.shiro.CredentialsMatcher;
import com.icesoft.system.auth.shiro.StatelessAccessControlFilter;
import com.icesoft.system.auth.shiro.StatelessSubjectFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.*;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

	@Resource
	private AuthRealm authRealm;

	@Resource
	private CredentialsMatcher credentialsMatcher;

	@Resource
	private RedisCacheManager redisCacheManager;

	@Bean
	@ConditionalOnMissingBean
	public AccessControlFilter shiroFilter() {
		return new StatelessAccessControlFilter(redisCacheManager);
	}

	@Bean
	@ConditionalOnMissingBean
	public DefaultWebSubjectFactory subjectFactory() {
		return new StatelessSubjectFactory();
	}

	@Bean
	@ConditionalOnMissingBean
	protected SessionStorageEvaluator sessionStorageEvaluator() {
		DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
		sessionStorageEvaluator.setSessionStorageEnabled(false);
		return sessionStorageEvaluator;
	}

	@Bean
	public DefaultWebSecurityManager defaultWebSecurityManager() {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		authRealm.setCredentialsMatcher(credentialsMatcher);
		manager.setRealm(authRealm);
		manager.setSubjectFactory(subjectFactory());
		((DefaultSubjectDAO) manager.getSubjectDAO()).setSessionStorageEvaluator(sessionStorageEvaluator());
		return manager;
	}

	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager) {
		ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
		filterFactoryBean.setSecurityManager(securityManager);
		Map<String, Filter> filterMap = new HashMap<>();
		filterMap.put("accessControlFilter", shiroFilter());
		filterFactoryBean.setFilters(filterMap);

		Map<String, String> map = new LinkedHashMap<>();
		map.put("/api/**", "anon");
		map.put("/auth/**", "anon");
		map.put("/common/**", "anon");
		map.put("/public/**", "anon");
		map.put("/wechat/**", "anon");
		map.put("/uploadFiles/**", "anon");
		map.put("/**", "accessControlFilter");

		filterFactoryBean.setFilterChainDefinitionMap(map);
		return filterFactoryBean;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Lazy SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager);
		return advisor;
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
		return creator;
	}
}
